/*==================Defines & Includes======================*/
#define _CRT_SECURE_NO_WARNINGS

#include <stdlib.h>
#include <WinSock2.h>
#include "ServerClientTools.h"
#include "SocketSendRecvTools.h"
#include "GeneralFunctions.h"
#include "Types.h"
#include "Algorithms.h"
#include "Hw4RandomNumbers.h"

#define MAX_NUMBER_OF_INTERCEPTORS 60//the maximum number of possible interceptors

/*=======================Structs===========================*/
//this struct is incharge of the conections to the simulator's clients 
typedef struct 
{
	SOCKET MainSocket;
	TInterceptorsList *InterceptorsList;
	SOCKET *ManagerSocket;
} TAcceptConncectionsArgsSimulator;

/*============Internal Functions Decleration=============*/

/*
 * Chasing Intercepor
 * =========================
 * This function checks if an interceptor is chasing a spesific rocket accordint to 
 * the Rocket ID.
 * Arguments: Rocket ID.
 * Return Value: A pointer to the chasing Interceptor if found or NULL. 
 */
TInterceptor* ChasingIntercepor(int RocketID);

/*
 * Update Interceptor List
 * =========================
 * This function while updateding the linked list of interceptors (a local paramater)
 * sends the active interceptors their location and informs interceptors
 * about interception attempts.
 * Arguments: None
 * Return Value: None
 */
void UpdateInterceptorList();

/*
 * Add Active Rocket
 * =========================
 * This function add's a created Rocket to a linked list of launched Rockets,
 * updateds its paramaters and set its status to Active. 
 * Arguments: Rocket ID				An Id for the Rocket 
 * 			  Initial Rocket Info	Initial information about the rocket's Launch location, Velocity and life time.
 * Return Value: A pointer to the created Rocket.
 */
TRocket* AddActiveRocket(int RocketID, TInitialRocketInfo InitialRocketInfo);

/*
 * Rockets Positions To Manager
 * ============================
 * Sends the position of all airborn rockets to the irondomemanager 
 * Arguments: IronDomeManager Socket
 * Return Value: None.
 */
void RocketsPositionsToManager(SOCKET ManagerSocket);

/*
 * Remove Rocket From List
 * =========================
 * This function romove a specific Rocket from a linked list of Rockets. 
 * Arguments: ExplodedRocket - A pointer to the Rocket we want to remove from the list
 * 			  PreviousRocket - A pointer to the Rocket before the Exploded Rocket.
 * Return Value: A pointer to the next Rocket after the one that exploded.
 */
TRocket* RemoveRocketFromList(TRocket* ExplodedRocket, TRocket* PreviousRocket);

/*
 * Interceptor Exploded
 * =========================
 *  This function romove a specific Interceptor from a linked list of LAunched Interceptors. 
 * Arguments: ExplodedInterceptor - A pointer to the Interceptor we want to remove from the list
 * 			  PreviousInterceptor - A pointer to the Interceptor  before the Exploded Intereceptor.
 * Return Value: A pointer to the Interceptor before the one that exploded if it was the first interceptor in the list it will return the new first.
 */
TInterceptor* InterceptorExploded(TInterceptor* ExplodedInterpetor, TInterceptor* PreviousInterpetor);

/*
 * Add Interceptor
 * =========================
 * This funcion initializes and adds a new interceptor node to a linked list of interceptors 
 * Arguments: Socket- The Socket of the new interceptor.	
 * Return Value: Head of the Interceptors linked list.
 */
TInterceptor* AddInterceptor(SOCKET Socket);

/*
 * Accept Connections To Simulator Thread
 * ======================================
 * This function is called on another thread, it will wait to receieve connectios from
 * clients - a manager and unknown number of interceptors.  
 * Arguments:*AcceptConnectionsArgs a struct with the relevent sockets and pointers for connections
 * Return Value: None
 */
void AcceptConnectionsToSimulatorThread(TAcceptConncectionsArgsSimulator *AcceptConnectionsArgs);

/*
 * Receive Info From Interceptor Thread
 * ====================================
 * This function Receives the Action from the interceptor and opporate accordingly
 * Arguments: *Interceptor	A pointer to the interceptor it is listening to 
 * Return Value: None
 */
void ReceiveInfoFromInterceptorThread(TInterceptor *Interceptor);

/*
 * Receive Info From Interceptors
 * ==============================
 * This function creates a thread for each interceptor and waits to
 * recieve updates from all the interceptors
 * by calling ReceiveInfoFromInterceptorThread function  
 * Arguments: global parameter.
 * Return Value: None
 */
void ReceiveInfoFromInterceptors();

/*
 * Count Active Rockets
 * =========================
 * this functions go throught the linked list of the rockets and
 * counts the number of active rockets.
 * Arguments: Global parameter.
 * Return Value: an integer of the number of flying rockets
 */
int CountActiveRockets();

/*
 * Print Simulation Output
 * =========================
 * Function Description: 
 * Arguments: IronDomeOutpit a File pointer to the text file.
 * 			  FirstInterceptor a pointer to the first Interceptor in the linked list.
 * Return Value: None
 */
void PrintSimulationOutput(TInterceptor* FirstInterceptor, FILE* IronDomeOutput);

/*
 * Delete Exploded Rockets
 * =========================
 * This functions go through the linked list of Rockets and deleters the exploded rockets from it 
 * Arguments: a Global parameter
 * Return Value: None
 */
void DeleteExplodedRockets();

/*====================Global Paramaters====================*/

// an ancor holding information on the linkes list of interceptors and a pointer to its head
TInterceptorsList InterceptorsList;
// an ancor holding information on the linkes list of Rockets and a pointer to its head
TRocketsList RocketsList;


/*=====================Main function=====================*/

void MainSimulator(int argc, char *argv[])
{	
	char *SelfIP = argv[2];
	int SelfPort = atoi(argv[3]);
	char *ClockIP = argv[4];
	int ClockPort = atoi(argv[5]);
	double MinX = atof(argv[6]);
	double MaxX = atof(argv[7]);
	double MinY = atof(argv[8]);
	double MaxY = atof(argv[9]);
	int MinT = atoi(argv[10]);
	int MaxT = atoi(argv[11]);
	double MinTheta = atof(argv[12]);
	double MaxTheta = atof(argv[13]);
	double MinV = atof(argv[14]);
	double MaxV = atof(argv[15]);
	double LaunchProbability = atof(argv[16]);
	double StandardDeviationVelocity = atof(argv[17]);
	double StandardDeviationPosition = atof(argv[18]);
	int N = atoi(argv[19]);//number of rockets
	int Seed;
	int NumberOfActiveRockets=0 , id =0, RoundNum;
	TInitialRocketInfo RocketInitialInfo;
	FILE* IronDomeOutput = NULL;
	SOCKET ClockSocket;
	SOCKET ManagerSocket;
	SOCKET MainSocket;
	HANDLE AcceptConnectcionsThreadHandle;
	TAcceptConncectionsArgsSimulator AcceptConncectionsArgsSimulator;
	TRocket *CurrentRocket = NULL;
	TInterceptor *CurrentInterceptor= NULL; 
	InterceptorsList.FirstInterceptor = NULL;
	InterceptorsList.NumOfInterceptors = 0;
	RocketsList.FirstRocket = NULL;
	RocketsList.NumOfRockets = 0;

	if (argc == 21)
	{
		Seed = atoi(argv[20]);
		printf("DEBUG: Optional seed has been given. Initializing random with seed: %d\n", Seed);
		InitializeRandomNumberGenerator(Seed);
	}
	else
	{
		InitializeRandomNumberGeneratorWithoutSeed();
	} 

	// Open outputfile
	IronDomeOutput = fopen("IronDomeOutput.txt","w"); 
	if (IronDomeOutput == NULL) 
	{
		PrintErrorAndExit(ERROR_WRITING_TO_FILE);
    }
	//Initializing Simulator as a server 
	MainSocket = StartServer(SelfIP, SelfPort);
	printf("Started a server. Waiting for clients to connect\n");
	
	// define arguments for the accept connections thread
	AcceptConncectionsArgsSimulator.MainSocket = MainSocket;
	AcceptConncectionsArgsSimulator.ManagerSocket = &ManagerSocket;
	
	printf("Waiting for interceptors and manager connect\n");
	AcceptConnectcionsThreadHandle = CreateThreadSimple((LPTHREAD_START_ROUTINE)AcceptConnectionsToSimulatorThread, &AcceptConncectionsArgsSimulator, NULL);
	if (AcceptConnectcionsThreadHandle==NULL)
		PrintErrorAndExit(ERROR_CREATING_THREAD);
	
	// InterceptorsList = AcceptConncectionsArgsSimulator.InterceptorsList;// I think this is unnecesary. matan
	printf("Connecting to clock\n");
	ClockSocket = StartClientAndConnectToServer(ClockIP, ClockPort);
	printf("Connected to clock\n");
	FinishedStartUpSequence();

	//recieve clock start
	RoundNum = WaitForClockToNotifyBeginningOfRound(ClockSocket);
	if (RoundNum == -1)
	{
		PrintErrorAndExit(ERROR_RECEIVING_MESSAGE);
	}
	
	while(1) 
	{
		// check if the game has ended
		if ((RocketsList.NumOfRockets == 0) && (InterceptorsList.NumOfInterceptors == 0) && (id == N))
		{
			fprintf(IronDomeOutput, "<<< END OF SIMULATION >>>");	
			fclose(IronDomeOutput); 
			SendActionType(ACTION_END_OF_GAME, ManagerSocket);
			closesocket(ClockSocket);
			PrintEndOfGame();	
			exit(1);
		}
		//Initialzing Rocket and Interceptor List to do actions per Rocket
		CurrentInterceptor = InterceptorsList.FirstInterceptor;
		CurrentRocket = RocketsList.FirstRocket;
		while (CurrentRocket != NULL)
		{	//============== a ===================
			// Calculating Rocket velocity
			printf("Current rocket ID: %d\n", CurrentRocket->RocketID);
			printf("Evaluating rocket %d velocity\n", CurrentRocket->RocketID);
			CurrentRocket->Velocity = EvaluateVelocity(CurrentRocket->Velocity,
													StandardDeviationVelocity);
			printf("New velocity: (%.3g, %.3g)\n", CurrentRocket->Velocity.x, CurrentRocket->Velocity.y);
			//============== b ===================
			//Calculating Rocket postion
			printf("Evaluating rocket %d position\n", CurrentRocket->RocketID);
			CurrentRocket->Position = EvaluatePosition(CurrentRocket->Position,
													   CurrentRocket->Velocity,
													   StandardDeviationPosition);
			printf("Rocket %d position: (%.3g, %.3g)\n", CurrentRocket->RocketID, CurrentRocket->Position.x, CurrentRocket->Position.y);
			//check to see if there is a chasing interceptor
			CurrentInterceptor = ChasingIntercepor(CurrentRocket->RocketID);
			if (CurrentInterceptor != NULL)
			{
				BOOL InterceptorDestroyed, RocketDestroyed;
				printf("Evaluating position of interceptor chasing rocket %d\n", CurrentRocket->RocketID);
				printf("INT POS OLD: %.3g, %.3g\n", CurrentInterceptor->Position.x, CurrentInterceptor->Position.y); 
				CurrentInterceptor->Position = EvaluatePosition(CurrentInterceptor->Position,
																CurrentInterceptor->Velocity,
																StandardDeviationPosition);
				printf("INT POS NEW: %.3g, %.3g\n", CurrentInterceptor->Position.x, CurrentInterceptor->Position.y);
				//printf("Interceptor chasing #%d position: (%.3g, %.3g)\n", CurrentRocket->RocketID, CurrentInterceptor->Position.x, CurrentInterceptor->Position.y);
				///============== c ===================
				//Check to see if Rocket has been intercepted
				printf("Checking if interception occured.\n");
				VerifyInterception(CurrentRocket->Position,
								   CurrentInterceptor->Position,
								   CurrentInterceptor->InterceptDistance,
								   CurrentInterceptor->SuccessRate,
								   &InterceptorDestroyed, &RocketDestroyed);
				if (InterceptorDestroyed == TRUE)
				{
					CurrentInterceptor->Status = M_STATUS_INTERCEPTED;
					if (RocketDestroyed == TRUE)
					{
						printf("Interceptor chasing #%d tried to intercept. SUCCESS!\n", CurrentInterceptor->RocketID);
						CurrentRocket->Status = M_STATUS_INTERCEPTED;
					}
					else if (RocketDestroyed == FALSE)
					{
						printf("Interceptor  chasing #%d tried to intercept but FAILED!\n", CurrentInterceptor->RocketID);
					}
					else
					{
						printf("Unknown result! error.\n");
					}
				}
				else if (InterceptorDestroyed == FALSE )//interceptor did not try to intercept
				{
					printf("No Attempted interception.\n");
				}
				else
				{
					printf("Unknown result! error.\n");
				}
			}
		
			//============== d =================== 
			// Check to see if Rocket hit the ground
			(CurrentRocket->LifeTime)-- ;
			if (CurrentRocket->LifeTime == 0 && CurrentRocket->Status != M_STATUS_INTERCEPTED)
			{
				printf("Rocket %d has hit the ground!\n", CurrentRocket->RocketID);
				CurrentRocket->Status = M_STATUS_HIT_GROUND;
				if (CurrentInterceptor != NULL)
					CurrentInterceptor->Status = M_STATUS_SELF_DESTRUCT; 
			}
			CurrentRocket = CurrentRocket->NextRocket;
			
			// next interceptor is being found inside the loop
			// if (CurrentInterceptor != NULL)
			// 	CurrentInterceptor = CurrentInterceptor->NextInterceptor;
			
		}
		//============== e ===================
		// new Rocket launches
		if (id < N)
		{
			BOOL DecisionRes = DecideIfLaunchRocket(&RocketInitialInfo, LaunchProbability,
			MinT,MaxT,MinX,MaxX,MinY,MaxY,MinTheta,MaxTheta,MinV,MaxV);
			if (DecisionRes == TRUE)
			{
				AddActiveRocket(id,RocketInitialInfo);
				id++;		
				printf("Rocket fired. ID: %d, Position: (%.3g, %.3g), Velocity: (%.3g, %.3g)\n"
					,id, RocketInitialInfo.InitialPosition.x, RocketInitialInfo.InitialPosition.y, 
					RocketInitialInfo.InitialVelocity.x, RocketInitialInfo.InitialVelocity.y);
			}
		}

		
		//============== f ===================
		//Update Interceptors on locations and interception occurrences
		UpdateInterceptorList();
		//============== g ===================
		// send active rockets map to manager
		RocketsPositionsToManager(ManagerSocket);

		//============== h ===================
		
		//end round
		SendActionType(ACTION_END_OF_ROUND, ManagerSocket);
		ReceiveInfoFromInterceptors();
		
		NotifyClockEndOfRound(ClockSocket);

		//============== Output ===================
		PrintSimulationOutput(InterceptorsList.FirstInterceptor, IronDomeOutput);
		DeleteExplodedRockets();
		
		//============= New Round =================
		//recieve clock start
		RoundNum = WaitForClockToNotifyBeginningOfRound(ClockSocket);
		if (RoundNum == -1)
		{
			PrintErrorAndExit(ERROR_RECEIVING_MESSAGE);
		}	
	}
}

/*======================Internal Functions======================*/

void ReceiveInfoFromInterceptors()
{
	int i = 0;
	HANDLE *ReceiveInfoThreadsHandles = NULL;
	TInterceptor *CurrentInterceptor = InterceptorsList.FirstInterceptor;
	int NumOfInterceptors = InterceptorsList.NumOfInterceptors;
	ReceiveInfoThreadsHandles = (HANDLE*)malloc(NumOfInterceptors*sizeof(HANDLE));
	if (ReceiveInfoThreadsHandles == NULL)
	{
		PrintErrorAndExit(ERROR_ALLOCATING_MEMORY);
	}
	while (CurrentInterceptor != NULL)
	{
		ReceiveInfoThreadsHandles[i] = CreateThreadSimple((LPTHREAD_START_ROUTINE) ReceiveInfoFromInterceptorThread, CurrentInterceptor,NULL);
		if (ReceiveInfoThreadsHandles[i] == NULL)
			PrintErrorAndExit(ERROR_CREATING_THREAD);
		CurrentInterceptor = CurrentInterceptor->NextInterceptor;
		i++;
	}
	printf("Created %d threads to listen to interceptors.\n", i);
	WaitForMultipleObjects(NumOfInterceptors, ReceiveInfoThreadsHandles, TRUE, INFINITE);
}

void ReceiveInfoFromInterceptorThread(TInterceptor *Interceptor)
{
	TActionType Action = ACTION_BEGINNING_OF_ROUND;
	SOCKET InterceptorSocket = Interceptor->Socket;
	
	while (Action != ACTION_END_OF_ROUND)
	{
		ReceiveActionType(&Action, InterceptorSocket);
		switch (Action)
		{
			case ACTION_INITIAL_INTERCEPTOR_INFO_UPDATE:
			{
				int RocketID;
				TVector Position, Velocity;
				double InterceptDistance, SuccessRate;
				ReceiveInteger(&RocketID, InterceptorSocket);
				ReceiveVector(&Position, InterceptorSocket);
				ReceiveVector(&Velocity, InterceptorSocket);
				ReceiveDouble(&InterceptDistance, InterceptorSocket);
				ReceiveDouble(&SuccessRate, InterceptorSocket);
				Interceptor->RocketID = RocketID;
				Interceptor->Position = Position;
				Interceptor->Velocity = Velocity;
				Interceptor->InterceptDistance = InterceptDistance;
				Interceptor->SuccessRate = SuccessRate;
				Interceptor->Status = M_STATUS_ACTIVE;
				ReceiveActionType(&Action, InterceptorSocket);
				if (Action == ACTION_UPDATE_CURRENT_DIRECTION)
				{
					TVelocity Velocity;
					ReceiveVector(&Velocity, InterceptorSocket);
					Interceptor->Velocity = Velocity;
					printf("VELOCITY UPDATE: %.3g %.3g\n", Interceptor->Velocity.x, Interceptor->Velocity.y );
				}
				else
				{
					printf("Error receiving info from interceptor\n");
				}
				break;
			}
			case ACTION_UPDATE_CURRENT_DIRECTION:
			{
				TVelocity Velocity;
				ReceiveVector(&Velocity, InterceptorSocket);
				Interceptor->Velocity = Velocity;
				printf("VELOCITY UPDATE: %.3g %.3g\n", Interceptor->Velocity.x, Interceptor->Velocity.y );
				break;
			}
			case ACTION_IN_BATTERY:
				printf("Interceptor is still in battery\n", Interceptor->RocketID);
				break;
			case ACTION_END_OF_ROUND:
				break;
			default:
				printf("Receiving actions from interceptor chasing #%d resulted in default case!\n", Interceptor->RocketID);
		}
	}
}


/*
 * ChasingInterceptor
 * =========================
 * Function Description: This function searches for the interceptor chasing a specific rocket, based on the rocket ID, in the interceptors list.
 * Arguments:  RocketID		the rocket ID
 * Return Value: A pointer to the chasing interceptor.
 */
TInterceptor* ChasingIntercepor(int RocketID)
{
	TInterceptor* CurrentInterceptor = InterceptorsList.FirstInterceptor;
	while ((CurrentInterceptor != NULL) && (CurrentInterceptor->RocketID != RocketID))
	{
		CurrentInterceptor = CurrentInterceptor->NextInterceptor;
	}
	return (CurrentInterceptor);
}

void UpdateInterceptorList()
{
	TInterceptor *CurrentInterceptor = InterceptorsList.FirstInterceptor;
	TInterceptor *PreviousInterceptor = InterceptorsList.FirstInterceptor;

	while(CurrentInterceptor != NULL )
	{
			switch (CurrentInterceptor->Status)
			{
			case M_STATUS_IN_BATTERY:
				PreviousInterceptor = CurrentInterceptor;
				CurrentInterceptor = CurrentInterceptor->NextInterceptor;
				break;
			case  M_STATUS_ACTIVE:
				SendActionType(ACTION_UPDATE_CURRENT_POSITION,CurrentInterceptor->Socket);
				SendVector(CurrentInterceptor->Position, CurrentInterceptor->Socket);
				PreviousInterceptor = CurrentInterceptor;
				CurrentInterceptor = CurrentInterceptor->NextInterceptor;
				break;
			case M_STATUS_INTERCEPTED:
				SendActionType(ACTION_INTERCEPTED,CurrentInterceptor->Socket); 
				CurrentInterceptor = InterceptorExploded(CurrentInterceptor,PreviousInterceptor);
				break;
			case M_STATUS_SELF_DESTRUCT:
				SendActionType(ACTION_UPDATE_CURRENT_POSITION, CurrentInterceptor->Socket);
				SendVector(CurrentInterceptor->Position, CurrentInterceptor->Socket);
				CurrentInterceptor = InterceptorExploded(CurrentInterceptor,PreviousInterceptor);
				break;
			}
	}
}

TInterceptor* AddInterceptor(SOCKET Socket)
{
	TInterceptor* NewInterceptor = (TInterceptor*)malloc(sizeof(TInterceptor));
    if(NewInterceptor == NULL)
	{
		PrintErrorAndExit(ERROR_ALLOCATING_MEMORY);
	}
	
	// initialize interceptor values
	if (InterceptorsList.FirstInterceptor != NULL)
		NewInterceptor->NextInterceptor = InterceptorsList.FirstInterceptor;
	else
		NewInterceptor->NextInterceptor = NULL;	
	
	NewInterceptor->Socket = Socket;
	NewInterceptor->Status = M_STATUS_IN_BATTERY;
	NewInterceptor->RocketID = -1;
	NewInterceptor->Velocity.x = 0;
	NewInterceptor->Velocity.y = 0;

	InterceptorsList.FirstInterceptor = NewInterceptor;	
	InterceptorsList.NumOfInterceptors++;
	return NewInterceptor;
}

TInterceptor* InterceptorExploded(TInterceptor* ExplodedInterpetor, TInterceptor* PreviousInterpetor)
{
	if(ExplodedInterpetor == InterceptorsList.FirstInterceptor)
	{
		InterceptorsList.FirstInterceptor = ExplodedInterpetor->NextInterceptor;
		free(ExplodedInterpetor);
		PreviousInterpetor = InterceptorsList.FirstInterceptor;
	}
	else
	{
		PreviousInterpetor->NextInterceptor = ExplodedInterpetor->NextInterceptor;
		free(ExplodedInterpetor);
	}
	InterceptorsList.NumOfInterceptors--;
	return PreviousInterpetor;
}

TRocket* AddActiveRocket(int RocketID, TInitialRocketInfo InitialRocketInfo)
{
	TRocket* Current = RocketsList.FirstRocket;
	TRocket* NewActiveRocket = NULL;
	
	// create new rocket
	NewActiveRocket = (TRocket*)malloc(sizeof(TRocket));
    if(NewActiveRocket == NULL)
		PrintErrorAndExit(ERROR_ALLOCATING_MEMORY);

	NewActiveRocket->RocketID = RocketID;
	NewActiveRocket->Status = M_STATUS_ACTIVE;
	NewActiveRocket->NextRocket = NULL;
	NewActiveRocket->LifeTime = InitialRocketInfo.FlightTime;
	NewActiveRocket->Position = InitialRocketInfo.InitialPosition;
	NewActiveRocket->Velocity = InitialRocketInfo.InitialVelocity;
	NewActiveRocket->Launched = TRUE;
	NewActiveRocket->Sightings = -1;
	NewActiveRocket->RocketType = ROCKET_TYPE_NULL;
	NewActiveRocket->ChasingBattery = NULL;

	if (RocketsList.FirstRocket == NULL)
	{
		RocketsList.FirstRocket = NewActiveRocket;
	}
	else
	{
		// go to the last rocket in the list
		while (Current->NextRocket != NULL)
			Current = Current->NextRocket;
		Current->NextRocket = NewActiveRocket;
	}
	RocketsList.NumOfRockets++;
	return NewActiveRocket;
}


void RocketsPositionsToManager(SOCKET ManagerSocket)
{
	TRocket *CurrentRocket = RocketsList.FirstRocket;
	TRocket *PreviousRocket = RocketsList.FirstRocket;
	int MessageSize = CountActiveRockets();
	SendActionType(ACTION_UPDATE_POSITIONS_MAP, ManagerSocket);
	SendInteger(MessageSize,ManagerSocket);

	while(CurrentRocket != NULL)
	{
		if (CurrentRocket->Status == M_STATUS_ACTIVE)
		{
				SendInteger(CurrentRocket->RocketID,ManagerSocket);
				SendVector(CurrentRocket->Position, ManagerSocket);
				PreviousRocket = CurrentRocket;
				CurrentRocket=CurrentRocket->NextRocket;
		}
		else
		{
			PreviousRocket = CurrentRocket;
			CurrentRocket=CurrentRocket->NextRocket;
		}
	}
}

void DeleteExplodedRockets()
{
	TRocket *CurrentRocket = RocketsList.FirstRocket;
	TRocket *PreviousRocket = RocketsList.FirstRocket;

	while(CurrentRocket != NULL)
	{
		switch (CurrentRocket->Status)
		{
			case  M_STATUS_ACTIVE:
				PreviousRocket = CurrentRocket;
				CurrentRocket=CurrentRocket->NextRocket;
				break;
			case M_STATUS_INTERCEPTED:
			{	
				printf("Rocket %d Intercepted at ( %.3g , %.3g ) \n",CurrentRocket->RocketID,CurrentRocket->Position.x,CurrentRocket->Position.y); 
				CurrentRocket = RemoveRocketFromList(CurrentRocket,PreviousRocket);
				break;
			}
			case M_STATUS_HIT_GROUND:
			{
				printf("Rocket %d Hit the ground at ( %.3g , %.3g ) \n",CurrentRocket->RocketID, CurrentRocket->Position.x, CurrentRocket->Position.y); 			
				CurrentRocket = RemoveRocketFromList(CurrentRocket,PreviousRocket);
				break;
			}
			default:
				PreviousRocket = CurrentRocket;
				CurrentRocket=CurrentRocket->NextRocket;
				break;
		}
	}
}

int CountActiveRockets()
{
	int count = 0;
	TRocket *CurrentRocket = RocketsList.FirstRocket;
	while (CurrentRocket != NULL)
	{
		if (CurrentRocket->Status == M_STATUS_ACTIVE)
		{
			count++;
		}
		CurrentRocket = CurrentRocket->NextRocket;
	}
	return count;
}

//frees the exploded rocket and returns the next rocket on the list
TRocket* RemoveRocketFromList(TRocket* ExplodedRocket, TRocket* PreviousRocket)
{

	if(ExplodedRocket == RocketsList.FirstRocket)
	{
		RocketsList.FirstRocket = ExplodedRocket->NextRocket;
		free(ExplodedRocket);
		PreviousRocket = RocketsList.FirstRocket;
		RocketsList.NumOfRockets--;
		return PreviousRocket;
	}
	else
	{
		PreviousRocket->NextRocket = ExplodedRocket->NextRocket;
		free(ExplodedRocket);
		RocketsList.NumOfRockets--;
		return PreviousRocket->NextRocket;
	}
}

// Recieve Connections from clients of interceptor or Manager modes
void AcceptConnectionsToSimulatorThread(TAcceptConncectionsArgsSimulator *AcceptConnectionsArgs)
{
	TInterceptor *AddedInterceptor = NULL;
	SOCKET MainSocket = AcceptConnectionsArgs->MainSocket;
	TMode Mode;
	
	while (1)
	{
		SOCKET Socket = AcceptConnection(MainSocket);
		ReceiveInteger((int*)&Mode, Socket);
		if(Mode == MODE_INTERCEPTOR)
		{
			AddedInterceptor = AddInterceptor(Socket);
			printf("Interceptor connected simulator \n");
		}
		else if (Mode == MODE_MANAGER)
		{
			*(AcceptConnectionsArgs->ManagerSocket) = Socket;
			printf("Manager connected simulator \n");	
		}
	}
}

/*================== Output ======================*/

//prints locations where Rocket hit the ground
void PrintFailedInterceptions(FILE* IronDomeOutput)
	{
		TRocket* CurrentRocket = RocketsList.FirstRocket;

		while (CurrentRocket != NULL)
		{
			if (CurrentRocket->Status == M_STATUS_HIT_GROUND)
			{
				fprintf(IronDomeOutput, "Attacker hit the ground at ( %.3g , %.3g )\n", CurrentRocket->Position.x,CurrentRocket->Position.y);
				// (RocketList->NumOfRockets)--;
			}			
			CurrentRocket = CurrentRocket->NextRocket;

		}
	}
//prints locations where Rocket were intercepted
void PrintSuccessInterceptions(FILE* IronDomeOutput)
	{
		TRocket* CurrentRocket = RocketsList.FirstRocket;

		while (CurrentRocket != NULL)
		{
			if (CurrentRocket->Status == M_STATUS_INTERCEPTED)
			{
				fprintf(IronDomeOutput, "Attacker was intercepted at ( %.3g , %.3g )\n", CurrentRocket->Position.x,CurrentRocket->Position.y);
			}			
			CurrentRocket = CurrentRocket->NextRocket;
		}
	}
//prints locations of chased Rockets and the Interceptor chasing them  
void PrintChasedRockets(TInterceptor* FirstInterceptor, FILE* IronDomeOutput)
	{
		TRocket* CurrentRocket = RocketsList.FirstRocket;
		TInterceptor* CurrentInterceptor = NULL;

		while (CurrentRocket != NULL)
		{
			CurrentInterceptor =ChasingIntercepor(CurrentRocket->RocketID) ;
			if ((CurrentRocket->Status == M_STATUS_ACTIVE) &&(CurrentInterceptor !=NULL))
			{
					fprintf(IronDomeOutput, "Attacker at ( %.3g , %.3g )\nchased by Interceptor at ( %.3g , %.3g )\n",
						CurrentRocket->Position.x,
						CurrentRocket->Position.y,
						CurrentInterceptor->Position.x,
						CurrentInterceptor->Position.y);
			}
			CurrentRocket = CurrentRocket->NextRocket;
		}
	}
//prints all locations of unchased Rockets			
void PrintUnchasedRockets(TInterceptor* FirstInterceptor,FILE* IronDomeOutput)
	{

		TRocket* CurrentRocket = RocketsList.FirstRocket;
		TInterceptor* CurrentInterceptor =FirstInterceptor;

		while (CurrentRocket != NULL)
		{
			CurrentInterceptor =ChasingIntercepor(CurrentRocket->RocketID) ;
			if ((CurrentRocket->Status == M_STATUS_ACTIVE) && (CurrentInterceptor == NULL))
			{
				fprintf(IronDomeOutput, "Attacker at ( %.3g , %.3g )\n",
						CurrentRocket->Position.x,
						CurrentRocket->Position.y);
			}
			CurrentRocket = CurrentRocket->NextRocket;
		}
	}

void PrintSimulationOutput(TInterceptor* FirstInterceptor, FILE* IronDomeOutput)
{
	fprintf(IronDomeOutput,"==== New Round ====\n");
	PrintFailedInterceptions(IronDomeOutput);
	PrintSuccessInterceptions(IronDomeOutput);
	PrintChasedRockets(FirstInterceptor,IronDomeOutput);
	PrintUnchasedRockets(FirstInterceptor, IronDomeOutput);
	printf("Number of Rockets in the air: %d\n",RocketsList.NumOfRockets);
}